home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / Unix / GopherTools / gmail.pl.Z / gmail.pl
Encoding:
Text File  |  1994-08-10  |  57.5 KB  |  1,819 lines

  1. news.utdallas.edu!wupost!newsfeed.rice.edu!rice!riddle Mon Mar 29 23:25:27 CST 1993
  2. Article: 1690 of comp.infosystems.gopher
  3. Xref: feenix.metronet.com comp.infosystems.gopher:1690
  4. Newsgroups: comp.infosystems.gopher
  5. Path: feenix.metronet.com!news.utdallas.edu!wupost!newsfeed.rice.edu!rice!riddle
  6. From: riddle@ruf.rice.edu (Prentiss Riddle)
  7. #Subject: gmail 1.01: mail-to-Gopherspace interface and events calendar
  8. Message-ID: <C4oL9y.Ct@rice.edu>
  9. Sender: news@rice.edu (News)
  10. Organization: Ministry of Information, William's Marsh
  11. Date: Tue, 30 Mar 1993 02:51:34 GMT
  12. Lines: 1803
  13.  
  14. Attached below is version 1.01 of gmail and gmailcal, a
  15. mail-to-Gopherspace interface and an accompanying tool which maintains
  16. an events calendar.
  17.  
  18. THIS INCLUDES IMPORTANT BUG FIXES OVER VERSION 1.0!!  If you are
  19. running gmail 1.0, you should install this in its place ASAP.
  20.  
  21. For details of changes, see the "history" at the head of each script.
  22. This release doesn't include many new features -- I concentrated on the
  23. bug fixes.  I did, however, include an auxiliary script called
  24. "gmailbatch" which is handy for submitting a number of items to gmail
  25. from a single file.
  26.  
  27. Again, many thanks to the folks who've given me feedback, encouragement
  28. and bug fixes...
  29.  
  30. -- Prentiss Riddle ("aprendiz de todo, maestro de nada") riddle@rice.edu
  31. -- Unix Systems Programmer, Office of Networking and Computing Systems
  32. -- Rice University, POB 1892, Houston, TX 77251 / Mudd 208 / 713-285-5327
  33. -- Opinions expressed are not necessarily those of my employer.
  34. -------------------------------------------------------------------------
  35. #! /bin/sh
  36. # This is a shell archive.  Remove anything before this line, then unpack
  37. # it by saving it into a file and typing "sh file".  To overwrite existing
  38. # files, type "sh file -c".  You can also feed this as standard input via
  39. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  40. # will see the following message at the end:
  41. #        "End of shell archive."
  42. # Contents:  gmail.8 gmailcal.8 gmail gmailcal gmailbatch
  43. # Wrapped by riddle@chico on Mon Mar 29 20:39:39 1993
  44. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  45. if test -f 'gmail.8' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'gmail.8'\"
  47. else
  48. echo shar: Extracting \"'gmail.8'\" \(7341 characters\)
  49. sed "s/^X//" >'gmail.8' <<'END_OF_FILE'
  50. X.TH GMAIL 8 Local
  51. X.SH NAME
  52. Xgmail - mail-to-Gopherspace interface
  53. X.RE
  54. X.SH SYNOPSIS
  55. X.B gmail
  56. X.B [-c]
  57. X.RE
  58. X.SH DESCRIPTION
  59. X.I Gmail
  60. Xis a perl(1) script which interprets an incoming mail message and,
  61. Xif it is acceptable, uses it to manipulate data in a Gopher data tree.
  62. X
  63. X.I Gmail
  64. Xexpects a Unix-style mail message on standard input.
  65. XIt uses the sender of the message (as determined from the From line)
  66. Xto determine whether the user is authorized to manipulate Gopher
  67. Xdata and, if so, the directory where their operations are to take place.
  68. X
  69. XAn authorized user can submit an item to Gopher by mailing it to
  70. X.I gmail
  71. Xwith the title on the Subject line and the data itself in the body of the
  72. Xmessage.  
  73. X.I Gmail
  74. Xwill map its title into a well-formed Unix filename (with no special
  75. Xcharacters to confuse the shell) and copy the data into that file.  It
  76. Xwill also create an associated
  77. X.B .cap
  78. Xfile to allow
  79. Xgopherd(8) to map the filename back to the title.
  80. XIf the file already exists,
  81. X.I gmail
  82. Xwill overwrite it.
  83. X
  84. XIf the first word of the subject is
  85. X.I delete
  86. X(or 
  87. X.I DELETE
  88. Xor some mixed-case
  89. Xequivalent), 
  90. X.I gmail
  91. Xwill generate a filename from the rest of the Subject line and delete it
  92. X(as well as the associated ``.cap'' file).
  93. X
  94. X.I Gmail
  95. Xperforms some stylistic checking: Gopher data submitted via
  96. X.I gmail
  97. Xmust consist entirely of printable ASCII characters and
  98. Xno lines in the message body may be over 80 characters long.
  99. X
  100. XWhen
  101. X.I gmail
  102. Xputs submitted data into a file in the Gopher data tree, it
  103. Xinserts the title as the first line of the file (this should make it easier
  104. Xto index data submitted by
  105. X.I gmail
  106. Xusing WAIS or some other full-text index software).
  107. X.I Gmail
  108. Xalso appends a byline in the form:
  109. X.nf
  110. X
  111. X   [Submitted by: Mojo Nixon (mojo@foo.edu)
  112. X                  Sun, 3 Jan 93 13:00:09 CST]
  113. X
  114. X.fi
  115. X.SH CALENDAR MODE
  116. XIf
  117. X.I gmail
  118. Xis invoked with a
  119. X.I -c
  120. Xoption, it will operate in ``calendar'' mode
  121. Xand will expect messages to be items for an events
  122. Xcalendar.  All operations
  123. Xperformed in calendar mode take place in a
  124. Xsingle directory within the Gopher data tree, defined by the
  125. X.B $caldir
  126. Xvariable in the
  127. X.I gmail
  128. Xscript.
  129. X
  130. XIn calendar mode,
  131. X.I gmail
  132. Xwill attempt to parse
  133. Xthe beginning of the Subject line (after an optional ``delete'' keyword)
  134. Xas a date, force it into a standard
  135. Xform, and use that together with the rest of the Subject line as
  136. Xa title.
  137. XDates are expected to be in the format
  138. X.I yy-mm-dd
  139. Xor
  140. X.I yyyy-mm-dd
  141. Xwhere
  142. X.I yy
  143. Xor
  144. X.I yyyy
  145. Xis the year,
  146. X.I mm
  147. Xis the month and
  148. X.I dd
  149. Xis the day.
  150. X.I Gmail
  151. Xhas a certain amount of flexibility in parsing dates; all
  152. Xof the following examples are equivalent:
  153. X.nf
  154. X
  155. X   93-01-04: Course registration begins
  156. X   93-1-4 Course registration begins
  157. X   1993/01/04 (Mon) : Course registration begins
  158. X
  159. X.fi
  160. XAll of these would be turned into the following Gopher title:
  161. X.nf
  162. X
  163. X   1993-01-04 (Mon): Course registration begins
  164. X
  165. X.fi
  166. X.RE
  167. X.SH DIAGNOSTICS
  168. X.I Gmail
  169. Xattempts to provide ample feedback to users and administrators
  170. Xentirely by electronic mail.
  171. XAll successful and unsuccessful operations result in mail being sent
  172. Xback to the sender, including both an explanatory
  173. Xmessage and the sender's original submission.
  174. XIn the case of delete operations, the deleted data is returned as well.
  175. XThis gives the sender a chance to catch mistakes and also
  176. Xto check for possible mail forgeries.
  177. XThe
  178. X.I gmail
  179. Xadministrator receives a copy in the event of errors and
  180. Xunauthorized admissions and, if the
  181. X.B $debug_admin
  182. Xvariable in the
  183. X.I gmail
  184. Xscript is defined, in normal successful operations as well.
  185. X
  186. XIn order to avoid mail loops,
  187. X.I gmail
  188. Xwill exit silently if it receives mail from root, postmaster or
  189. Xthe mailer-daemon or if the subject line appears to be an error message.
  190. X.RE
  191. X.SH ACCESS CONTROL
  192. X.I Gmail
  193. Xuses a static file (defined by the
  194. X.B $gmailers
  195. Xvariable at the beginning of the perl(1) script)
  196. Xto determine who is authorized to use the gmail interface and
  197. Xwhere their data is to go.  Each line of this ``gmailers'' file is
  198. Xin the following format:
  199. X
  200. X   sender's-email-address [calendar] [directory]
  201. X
  202. XIf the ``calendar'' keyword is present, the user is authorized to
  203. Xsubmit calendar events via a gmail process running in calendar mode.
  204. XIf a directory is specified, the user is authorized to submit
  205. Xdata to that directory.  Only one directory may be specified per user.
  206. XThe format of the file also allows for blank lines and comments beginning
  207. Xwith ``#''.  Example:
  208. X.nf
  209. X
  210. X   # This is a sample gmailers file.
  211. X   tjones@foo.edu /foo1/gopher-data/policy         # directory only
  212. X   nsinatra@bar.edu calendar                       # calendar only
  213. X   mojo@foo.edu calendar /foo1/gopher-data/policy  # both
  214. X
  215. X.fi
  216. X.RE
  217. X.SH INSTALLATION
  218. X.I Gmail
  219. Xis best installed by being invoked from a
  220. X.B .forward
  221. Xfile in the home directory of a pseudo-user with write permission
  222. Xin the portions of the Gopher data tree where
  223. X.I gmail
  224. Xis to deliver data.
  225. X(The
  226. X.B .forward
  227. Xfile must be owned by the pseudo-user or the mail system will ignore it.)
  228. X
  229. XFor example, consider the following /etc/passwd entries for
  230. Xthe machine foo.edu:
  231. X.nf
  232. X
  233. X   cwis:*:999:20:CWIS Operator:/foo/cwis:/bin/csh
  234. X   cwis-mail:*:999:20:CWIS Operator:/foo/cwis/cwis-mail:/bin/csh
  235. X   cwis-cal:*:999:20:CWIS Operator:/foo/cwis-cal:/bin/csh
  236. X
  237. X.fi
  238. XIf ~cwis-mail/.forward contains the following (the quotes are necessary):
  239. X.nf
  240. X
  241. X   "| /usr/local/etc/gmail"
  242. X
  243. X.fi
  244. Xand ~cwis-cal/.forward contains the following:
  245. X.nf
  246. X
  247. X   "| /usr/local/etc/gmail -c"
  248. X
  249. X.fi
  250. Xthen authorized users can submit ordinary Gopher items
  251. Xby mailing them to ``cwis-mail@foo.edu''
  252. Xand submit calendar items by mailing them to ``cwis-cal@foo.edu''.
  253. X.RE
  254. X.SH CONFIGURATION
  255. XThe following perl(1) variables must be set according to the needs of
  256. Xyour site at the beginning of the
  257. X.I gmail
  258. Xscript (see the comments in the script for more details):
  259. X.TP
  260. X.B @safedir
  261. XA list of directories under which it is acceptable to deliver data
  262. X(usually just the root of your Gopher data tree).
  263. X.TP
  264. X.B $caldir
  265. XThe directory where calendar data is to be placed.
  266. X.TP
  267. X.B $gmailers
  268. XThe name of the file containing authorized users
  269. Xand their target directories.
  270. X.TP
  271. X.B $publiccal
  272. XA switch to determine whether people submitting calendar items
  273. Xmust be authorized and listed in the $gmailers file.
  274. X.TP
  275. X.B $prob_admin
  276. XThe electronic mail address of the Gopher administrator to be notified
  277. Xin case of errors and unathorized submissions.
  278. X.TP
  279. X.B $debug_admin
  280. XThe electronic mail address of the Gopher administrator to be notified
  281. Xin case of normal, successful submissions.
  282. X.TP
  283. X.B $MAIL
  284. XThe preferred mail program on your system (probably /bin/mail).
  285. X.TP
  286. X.B $server_name
  287. XA short descriptive name of your Gopher server.
  288. X.TP
  289. X.B $sig
  290. XGopher administrator contact info.
  291. X.TP
  292. X.B $disclaimer
  293. XAn optional disclaimer to be appended to each item saved in Gopherspace.
  294. X.TP
  295. X.B $UMASK
  296. XThe Unix file permissions mask.  Use 002 if you wish to have
  297. Xfiles created by gmail be group-writeable, 022 otherwise.
  298. X.RE
  299. X.SH "BUGS"
  300. XReturns a copy of deleted data but not overwritten data; doesn't save
  301. Xa copy of either one.
  302. X
  303. XAccepts a single date in calendar mode but not a range of dates.
  304. X
  305. XRelies on mail to inform administrator of problems; has no logging.
  306. X.RE
  307. X.SH "SEE ALSO"
  308. Xgmailcal(8),
  309. Xgopherd(8),
  310. Xperl(1)
  311. X.SH AUTHORS
  312. XPrentiss Riddle (riddle@rice.edu)
  313. X
  314. XSome code gratefully borrowed from the
  315. X.I audit.pl
  316. Xpackage by Martin Streicher (strike@convex.com).
  317. END_OF_FILE
  318. if test 7341 -ne `wc -c <'gmail.8'`; then
  319.     echo shar: \"'gmail.8'\" unpacked with wrong size!
  320. fi
  321. # end of 'gmail.8'
  322. fi
  323. if test -f 'gmailcal.8' -a "${1}" != "-c" ; then 
  324.   echo shar: Will not clobber existing file \"'gmailcal.8'\"
  325. else
  326. echo shar: Extracting \"'gmailcal.8'\" \(4290 characters\)
  327. sed "s/^X//" >'gmailcal.8' <<'END_OF_FILE'
  328. X.TH GMAIL-CAL 8 Local
  329. X.SH NAME
  330. Xgmailcal - organize an events calendar maintained with gmail(8l)
  331. X.RE
  332. X.SH SYNOPSIS
  333. X.B gmailcal
  334. X.RE
  335. X.SH DESCRIPTION
  336. X.I Gmailcal
  337. Xis a perl(1) script which organizes a calendar of events submitted
  338. Xvia the mail-to-Gopherspace interface gmail(8).
  339. X
  340. X.I Gmailcal
  341. Xis intended to be run shortly after midnight each night from crontab.
  342. XIt performs maintenance functions on a directory of calendar event files
  343. Xcreated by
  344. X.I gmail
  345. Xand creates Gopher links constituting alternate views of the upcoming
  346. Xevents organized by date.  The result should be a Gopher menu structure
  347. Xwhich looks like this:
  348. X.nf
  349. X
  350. X   Foobar University events schedule/
  351. X      About the Foobar University events schedule
  352. X      Today/
  353. X      Tomorrow/
  354. X      This week/
  355. X      Next week/
  356. X      January, 1993/
  357. X      February, 1993/
  358. X      March, 1993/
  359. X      April, 1993/
  360. X      May, 1993/
  361. X      All upcoming events/
  362. X      Past events/
  363. X
  364. X.fi
  365. XThe ``All upcoming events'' directory contains the actual events files
  366. Xstored by
  367. X.I gmail.
  368. XEvents for dates which have already taken place are moved by 
  369. X.I gmailcal
  370. Xinto the ``Past events'' directory, where they are kept for a configurable
  371. Xnumber of days and then deleted.
  372. XThe other directories (``Today'', ``Tomorrow'', etc.) contain
  373. XGopher links to the appropriate events in the ``All upcoming events''
  374. Xdirectory.
  375. X
  376. X.I Gmailcal
  377. Xalso creates a Gopher link in each directory to the
  378. X``About'' file in the parent directory, which should contain a
  379. Xdescription of the events calendar and how to submit items to it.
  380. X.RE
  381. X.SH CONFIGURATION
  382. XThe following perl(1) variables must be set according to the needs of
  383. Xyour site at the beginning of the
  384. X.I gmailcal
  385. Xscript (see the comments in the script for more details):
  386. X.TP
  387. X.B $caldir
  388. XThe directory where
  389. X.I gmail
  390. Xplaces events calendar data
  391. X(the same variable must be set in the
  392. X.I gmail
  393. Xscript).  It should probably end in
  394. Xthe word ``Upcoming'' (for example, ``/foo/gopher/events/Upcoming'').
  395. XThe alternate views created by
  396. X.I gmailcal
  397. Xwill go into sibling
  398. Xdirectories relative to $caldir (for example, ``../Today'').
  399. X.TP
  400. X.B $Host
  401. XThe hostname of the host running the Gopher server which will serve out
  402. Xthe events calendar.
  403. X.TP
  404. X.B $Port
  405. XThe TCP/IP port number of the Gopher server.
  406. X.TP
  407. X.B $Path
  408. XThe Gopher's-eye view of the same directory specified in $caldir, including
  409. Xthe initial type specifier ``1''.
  410. XExample: ``1/events/Upcoming''.
  411. X.TP
  412. X.B $keepold
  413. XThe number of days to keep old events in the ``Past'' directory
  414. Xbefore deleting them.
  415. X.TP
  416. X.B $weekbreak
  417. XThe day of the week on which the week begins (0 for Sunday, 1 for Monday).
  418. X.TP
  419. X.B $monthviews
  420. XThe number of months ahead to maintain month-by-month views.
  421. X.TP
  422. X.B $description
  423. XA short description of the events calendar
  424. X(e.g., ``the Foobar University events schedule'').
  425. X.TP
  426. X.B $debug
  427. XSet to 1 to receive extensive debug output, 0 to
  428. Xreceive only serious error messages.
  429. X.TP
  430. X.B $UMASK
  431. XThe Unix file permissions mask.  Use 002 if you wish to have
  432. Xfiles created by gmailcal be group-writeable, 022 otherwise.
  433. X.RE
  434. X.SH "FULL-TEXT INDEXES"
  435. X.I Gmailcal
  436. Xdoes not create a full-text index of the events data, but you can
  437. Xuse WAIS or your favorite software to do so.
  438. X.I Gmail
  439. Xinserts the title of each item as the first line of each file it
  440. Xputs into Gopherspace, so the WAIS "-t first_line" should be useful.
  441. X.RE
  442. X.SH DIAGNOSTICS
  443. X.I Gmailcal
  444. Xproduces error messages on stderr.  It will operate silently if there
  445. Xare no errors, unless the
  446. X.B $debug
  447. Xperl variable in the
  448. X.I gmailcal
  449. Xscript is turned on, in which
  450. Xcase it will produce copious information about everything it does.
  451. X.RE
  452. X.SH "FILES"
  453. XThe actual filenames of the various files and
  454. Xdirectories (relative to $caldir) are:
  455. X.nf
  456. X
  457. X   ../About
  458. X   ../Today
  459. X   ../Tomorrow
  460. X   ../This_week
  461. X   ../Next_week
  462. X   ../yyyy-mm (for the month-by-month views)
  463. X   ../Past
  464. X
  465. X.fi
  466. XWithin each directory,
  467. X.I gmailcal
  468. Xcreates ``.links'' files and/or ``.cap'' subdirectories.
  469. X.RE
  470. X.SH "BUGS"
  471. XThe gopherd(8) Gopher server can easily become very confused about the
  472. Xorder of items if there are problems with ``Numb='' entries in .cap files.
  473. X
  474. XIf there are no events in a given month, it would be nice if that directory
  475. Xdid not appear at all.
  476. X.RE
  477. X.SH "SEE ALSO"
  478. Xgmail(8),
  479. Xgopherd(8),
  480. Xperl(1),
  481. Xcrontab(1),
  482. Xcrontab(5).
  483. X.SH AUTHOR
  484. XPrentiss Riddle (riddle@rice.edu)
  485. END_OF_FILE
  486. if test 4290 -ne `wc -c <'gmailcal.8'`; then
  487.     echo shar: \"'gmailcal.8'\" unpacked with wrong size!
  488. fi
  489. # end of 'gmailcal.8'
  490. fi
  491. if test -f 'gmail' -a "${1}" != "-c" ; then 
  492.   echo shar: Will not clobber existing file \"'gmail'\"
  493. else
  494. echo shar: Extracting \"'gmail'\" \(26490 characters\)
  495. sed "s/^X//" >'gmail' <<'END_OF_FILE'
  496. X#!/usr/local/bin/perl
  497. X#
  498. X#  gmail: mail-to-Gopherspace interface
  499. X#
  500. X#  usage:  gmail [-c]
  501. X#
  502. X#  PASR 12/28/92  Rough draft.
  503. X#  PASR 12/31/92  Initial test installation.
  504. X#  PASR 01/03/93  Added DELETE function.
  505. X#  PASR 01/05/93  Reworded authorization rejection message.
  506. X#  PASR 01/05/93  Forced sender's address to lowercase for easy matching.
  507. X#  PASR 01/08/93  Declared this release 0.1 for beta testing.
  508. X#  PASR 01/15/93  Fixed bug caused by perl's inability to write to long
  509. X#                 paths; removed $caldir_by_date; made year in output
  510. X#                 format be yyyy instead of yy to facilitate sorting.
  511. X#  PASR 02/02/93  Added the title line to the body of each file saved
  512. X#                 to facilitate WAIS indexing.
  513. X#  PASR 02/03/93  Changed "From" lines to ">From" in header in order
  514. X#                 to avoid confusing mailers when we send out feedback.
  515. X#                 Reversed the logic of the test in &check_target (it was
  516. X#                 bogus).
  517. X#                 Declared this release 0.2 for further beta testing.
  518. X#  PASR 02/04/93  Force addresses in $gmailers file to lower case since
  519. X#                 the gmail administrator can't be counted on to remember
  520. X#                 to do so. :-)
  521. X#  PASR 02/05/93  Added "$publiccal" mode: if it is turned on, submissions
  522. X#                 in calendar mode require no authorization in the $gmailers
  523. X#                 file (although deletions still do).
  524. X#                 Added an optional "$disclaimer".
  525. X#  PASR 02/22/93  Declared this release 1.0 for general use.
  526. X#  PASR 03/07/93  Fixed security problem by quoting $sender in mail pipe.
  527. X#                 Attempt to prevent mail loops when error messages bounce
  528. X#                 back to gmail.
  529. X#                 Fixed whitespace cleanup in &normalize.
  530. X#                 Don't allow tabs in Name= fields in .cap files
  531. X#                 (reportedly gopherd can be confused by them).
  532. X#                 Unlink data file if corresponding .cap file can't be made.
  533. X#  PASR 03/09/93  Create .cap files only when necessary.
  534. X#                 Moved misplaced unlink() calls to take place before &abends.
  535. X#  PASR 03/12/93  Removed unnecessary &initialize call; just use &parse_message.
  536. X#  PASR 03/29/93  Declared this version 1.01.
  537. X#
  538. X#  TODO: Think about cleaning up &delete_it() (should move aside old
  539. X#        data rather than just gobbling it into memory).
  540. X#  TODO: Think about screening for binhex and other ASCIIfied binary formats.
  541. X#  TODO: Think about extending the "public calendar" mode to cover
  542. X#        non-calendar items as well (a "public" mode which puts data into
  543. X#        a "$publicdir" directory).
  544. X#  TODO: Think about including a command-line option which causes header
  545. X#        info to be read from a file, allowing a single installation to
  546. X#        be used in multiple configurations (in particular, to allow
  547. X#        multiple events calendars).
  548. X#  TODO: Think about a reasonable way to specify multiple target directories
  549. X#        per sender.  (Hairball!)
  550. X#  TODO: Think about notifying the original submitter if someone else
  551. X#        deletes or overwrites her data.
  552. X#  TODO: Think about using $address instead of/in addition to $sender
  553. X#        for address matching.
  554. X#  TODO: Think about a way to handle directory names in the gmailers file
  555. X#     containing whitespace or # signs.
  556. X#  TODO: Add better date checking (eliminate "Feb 30", etc.).
  557. X
  558. X#--------------------------------------------------------------------------
  559. X# CONFIGURATION: modify these to suit your site!
  560. X
  561. X# All targets must live under a directory in this list.
  562. X# (EXAMPLE: @safedir = ("/foo/bar/dir1", "/foo/bar/dir2");
  563. X@safedir = ("/foo/cwis/gopher/world", "/foo/cwis/gopher/rice",
  564. X            "/foo/cwis/gopher/test");
  565. X
  566. X# Calendar data live under here (only needed if calendar mode is turned on)
  567. X$caldir = "/foo/cwis/gopher/world/Calendars/Events/Upcoming";
  568. X
  569. X# File which lists authorized users and their target directories:
  570. X$gmailers = "/foo/cwis/gopher/etc/gmailers";
  571. X
  572. X# Public calendar switch: if this is set to 1, items submitted in calendar
  573. X# mode (the "-c" flag) will not require authorization in the $gmailers file.
  574. X# Deletions and non-calendar items will still require authorization.
  575. X# This option is irrelevant if you are not running in calendar mode.
  576. X$publiccal = 0;
  577. X
  578. X# Administrator to notify in case of errors or unauthorized submissions:
  579. X$prob_admin = "jdoe@foobar.edu";
  580. X
  581. X# Administrator to notify of *every* submission (leave this undefined if
  582. X# you only want to hear about problems):
  583. X$debug_admin = "jdoe@foobar.edu";
  584. X
  585. X# Preferred mailer program.  Must accept recipients' addresses on command
  586. X# line and "Subject:" line on standard input.
  587. X$MAIL = "/bin/mail";
  588. X
  589. X# A short descriptive name of your Gopher server for use in feedback and
  590. X# error messages.  It should be under 40 characters for best results.
  591. X$server_name = "the FooInfo Gopher server";
  592. X
  593. X# Gopher administrator contact info and signature for use in feedback and
  594. X# error messages.
  595. X$sig =
  596. X"To contact the FooInfo Gopher administrator with questions, problems
  597. Xor suggestions, send mail to fooinfo@foobar.edu or call the Consulting
  598. XCenter at 527-4983.
  599. X
  600. X-- FooInfo Gopher Administrator, Information Systems, fooinfo@foobar.edu
  601. X-- This message was automatically generated.
  602. X";
  603. X
  604. X# Optional disclaimer to be appended to each item saved in Gopherspace.
  605. X# Leave it blank if you don't need a ubiquitous disclaimer.
  606. X#$disclaimer = "[Foobar University is not responsible for this stuff.]";
  607. X$disclaimer = "";
  608. X
  609. X# Umask: the Unix file permissions mask.  Use 002 if you wish to have
  610. X# files created by gmail be group-writeable, 022 otherwise.
  611. X$UMASK = 022;
  612. X
  613. X#--------------------------------------------------------------------------
  614. X# Feedback and error messages.  You can tinker with these if you like,
  615. X# but it shouldn't be necessary.
  616. X
  617. X# Acceptance message.
  618. X$accept_msg =
  619. X"Your submission was posted to $server_name.
  620. XPlease use Gopher to check it and make sure it looks as you
  621. Xintended.  If it does not, please submit it again.
  622. X
  623. XIf you did *not* submit this request, it may mean that someone has been
  624. Xforging electronic mail in your name.  Please contact the Gopher
  625. Xadministrator immediately.
  626. X";
  627. X
  628. X# Authorization message.
  629. X$auth_msg =
  630. X"Your submission was not accepted for $server_name
  631. Xbecause you have not been authorized to submit data by mail from this
  632. Xe-mail address.  If you would like to sign up to do so, please contact
  633. Xthe Gopher administrator.
  634. X";
  635. X
  636. X# Date message.
  637. X$date_msg =
  638. X"Your announcement was not accepted for $server_name
  639. Xbecause the subject line did not contain an appropriately formatted
  640. Xdate.  The subject line must begin with a date in the format
  641. X\"yy-mm-dd\" or \"yyyy-mm-dd\".  For example:
  642. X
  643. X     Subject: 92-10-31: Institutional Halloween Party
  644. X
  645. X     Subject: 2001-01-10: Twenty-first Century Lecture
  646. X
  647. XPlease reformat the date in your subject line and resubmit your
  648. Xannouncement.
  649. X";
  650. X
  651. X# Deletion acknowledgement.
  652. X$del_ack_msg =
  653. X"Your request to delete data in $server_name
  654. Xwas accepted.  Please check the data below and make sure that it was
  655. Xwhat you intended to delete.
  656. X
  657. XIf you did *not* request that this item be deleted, it may mean that
  658. Xsomeone has been forging electronic mail in your name.  Please save
  659. Xthis message and contact the Gopher administrator immediately.
  660. X";
  661. X
  662. X# Deletion error message.
  663. X$del_err_msg =
  664. X"Your deletion request for data in $server_name
  665. Xwas not processed because of the following error:
  666. X";
  667. X
  668. X# Error message.
  669. X$error_msg =
  670. X"Your submission was not accepted for $server_name
  671. Xbecause of the following error:
  672. X";
  673. X
  674. X# Style message.
  675. X$style_msg =
  676. X"Your submission was not accepted for $server_name
  677. Xbecause either (1) it is not strictly printable ASCII text or (2) it
  678. Xcontains lines which are greater than 80 columns in length.  Please
  679. Xreformat your data appropriately and resubmit it.
  680. X";
  681. X
  682. X# Separators for displaying the submitted item.
  683. X$subsep = "-------------------- Submitted request follows --------------------";
  684. X$subend = "-------------------- End of submitted request ---------------------";
  685. X$delsep = "---------------------- Deleted item follows -----------------------";
  686. X$delend = "---------------------- End of deleted item ------------------------";
  687. X
  688. X#--------------------------------------------------------------------------
  689. X
  690. X# Further initialization.  Don't mess with this.
  691. Xrequire("ctime.pl");
  692. Xrequire("timelocal.pl");
  693. X$auth = 0;            # Is the sender authorized?
  694. X$calendar = 0;            # Are we in calendar mode? ("-c" option)
  695. X$delete = 0;            # Are we in delete mode? ("DELETE" keyword)
  696. X$usage = "usage: gmail [-c]";
  697. Xumask $UMASK;
  698. X$loopsenders = '^(root|mailer-daemon|postmaster)\b';
  699. X                # senders who may mean we're in a mail loop
  700. X
  701. X# Now we're rolling...
  702. X
  703. X# Refuse to run as root.
  704. X&abend("Data not accepted for Gopher due to gmail error",
  705. X    $error_msg . "gmail should not be run as root.\n")
  706. X    if ($> == 0);
  707. X
  708. X# Process command-line options.
  709. XARGS:
  710. Xwhile ($#ARGV >= 0) {
  711. X    $arg = $ARGV[0];
  712. X    shift;
  713. X    if ($arg eq "-c") {
  714. X        $calendar = 1;
  715. X        next ARGS;
  716. X    }
  717. X    &abend("Data not accepted for Gopher due to gmail error",
  718. X        $error_msg . "Unrecognized command-line option: $arg\n\n"
  719. X        . $usage);
  720. X}
  721. X
  722. X# Parse the incoming message.  Global variables returned which we will use:
  723. X#   $body  $friendly  @headers  $header  $sender  $subject
  724. X&parse_message(STDIN);
  725. X$header =~ s/^From/>From/;    # Don't want to confuse mailer in feedback
  726. X$subject =~ tr/\t/ /;        # Tabs could confuse gopherd.
  727. X$sender =~ s/'//g;        # We'll want to enclose $sender in 's later.
  728. X&abend("Data not accepted for Gopher due to gmail error",
  729. X    $error_msg . "Sender not defined in mail header.\n")
  730. X    unless ($sender);
  731. Xif ($sender =~ /$loopsenders/io || 
  732. X    $subject =~ /(returned mail|user unknown)/i) {
  733. X    # We may be in a mail loop.  We can't abend the normal way because
  734. X    # that could perpetuate the loop.  We try to signal our distress
  735. X    # via other methods, then exit without acknowledging the message.
  736. X    system("/usr/ucb/logger -i -p mail.error gmail in possible mail loop with '$sender'")
  737. X         if (-x "/usr/ucb/logger");
  738. X    exit(0);
  739. X}
  740. X
  741. X# Try to match the sender in the list of authorized users.
  742. X$target = &check_auth();
  743. X
  744. X# See if this is a delete request.
  745. X# If so, this will modify the $subject accordingly.
  746. X$delete = &parse_delete();
  747. X
  748. X# If we're in calendar mode, parse the subject line for a date.
  749. X# This will modify the $subject and $target accordingly.
  750. X&parse_date() if ($calendar);
  751. X
  752. X# Check $target to make sure it safely falls within @safedir.
  753. X&check_target($target);
  754. X
  755. X# Carry out the deletion and exit if we're in delete mode.
  756. X$filename = &normalize($subject);
  757. X&delete_it() if $delete;
  758. X
  759. X# Check style of title and data.
  760. X&check_style($subject, $body);
  761. X
  762. X# Write the file and the associated .cap file.
  763. X$byline = "\n[Submitted by: $friendly ($sender)\n               $headers{'date'}]\n";
  764. X&write_it();
  765. X
  766. X# Give the user some positive feedback.
  767. X&feedback();
  768. X
  769. X# Normal end.
  770. Xexit 0;
  771. X
  772. X#--------------------------------------------------------------------------
  773. X# abend -- mail an error message to the sender and administrator and exit
  774. X#
  775. X# This will alert the administrator even if $sender has not yet been
  776. X# defined...
  777. X#
  778. X# usage:  &abend($shortmsg, $longmsg);
  779. X# Global variables used:
  780. X#      $body $header $sender $MAIL $subend $subsep $prob_admin
  781. X
  782. Xsub abend {
  783. X    local($shortmsg, $longmsg) = @_;
  784. X    if ($sender && sender !~ /$loopsenders/io) {
  785. X        open (MAIL, "| $MAIL $prob_admin '$sender'");
  786. X    } else {
  787. X        open (MAIL, "| $MAIL $prob_admin");
  788. X    }
  789. X    print MAIL "Subject: $shortmsg\n\n";
  790. X    print MAIL "$longmsg\n$sig\n\n";
  791. X    print MAIL "$subsep\n";
  792. X    print MAIL "$header";
  793. X    print MAIL "$body";
  794. X    print MAIL "$subend\n";
  795. X    close(MAIL);
  796. X    # We'd like to exit here with an error but it confuses sendmail...
  797. X    exit 0;
  798. X}
  799. X#--------------------------------------------------------------------------
  800. X# check_auth -- look up user in list of authorized gmailers
  801. X#
  802. X# usage:    $target = &check_auth()
  803. X# returns:  target directory ($caldir if we are in calendar mode)
  804. X#
  805. X# side effect: forces $sender to lower case
  806. X# global variables used:
  807. X#      $calendar $caldir $error_msg $gmailers $auth_msg $sender $target
  808. X#         $delete $publiccal
  809. X
  810. Xsub check_auth {
  811. X    local($auth, $targ, $matchaddr);
  812. X
  813. X    # If we are in calendar mode and *not* in delete mode and the
  814. X    # "$publiccal" switch is turned on, no further authorization is
  815. X    # necessary.
  816. X    return ($caldir) if ($calendar && !$delete && $publiccal);
  817. X
  818. X    $sender =~ tr/A-Z/a-z/;        # ignore case for easy matching
  819. X    open (GMAIL, $gmailers) ||
  820. X        &abend("Data not accepted for Gopher due to gmail error",
  821. X            $error_msg . "Can't open gmailers file $gmailers\n$@");
  822. X    while (<GMAIL>) {
  823. X        ($matchaddr) = /^(\S*)/;
  824. X        $matchaddr =~ tr/A-Z/a-z/;    # ignore case
  825. X        if ($matchaddr eq $sender) {
  826. X            # carve what we want out of the current line
  827. X            s/\s*#.*//;    # remove comments;
  828. X            s/\s+$//;    # remove final whitespace;
  829. X            s/^\s*\S*\s+//;    # remove initial whitespace
  830. X                    # and sender's address
  831. X            if ($calendar) {
  832. X                # Look for the "calendar" keyword
  833. X                $auth = (/\bcalendar\b/);
  834. X                $targ = $caldir;
  835. X            } else {
  836. X                # Remove the "calendar" keyword
  837. X                s/\s*calendar\s*//;
  838. X                $auth = $targ = $_;
  839. X            }
  840. X            last;
  841. X        }
  842. X    }
  843. X    close(GMAIL);
  844. X    unless ($auth) {
  845. X        if ($calendar) {
  846. X            &abend("Not authorized to submit data to Gopher events calendar", $auth_msg);
  847. X        } else {
  848. X            &abend("Not authorized to submit data to Gopher", $auth_msg);
  849. X        }
  850. X    }
  851. X    return($targ);
  852. X}
  853. X#--------------------------------------------------------------------------
  854. X# check_style -- check to make sure that the style is acceptable 
  855. X#                (i.e., that the subject and body consist of printable ASCII
  856. X#                characters and the lines in the body are all <80 chars wide).
  857. X#                Exit with an error message if it is not.
  858. X#
  859. X# usage:   &check_style($subject, $body)
  860. X
  861. Xsub check_style {
  862. X    local($subject, $body) = @_;
  863. X    local($line, $okay, $unprintables);
  864. X    $unprintables = "[\000-\010\012-\037]";
  865. X
  866. X    $okay = 1;
  867. X    $okay = 0 if ($subject =~ /$unprintables/o);
  868. X    foreach $line (split(/\n/, $body)) {
  869. X        if ((length($line) >= 80) || ($line =~ /$unprintables/o)) {
  870. X            $okay = 0;
  871. X            last;
  872. X        }
  873. X    }
  874. X    &abend("Data not accepted for Gopher: style problems", $style_msg)
  875. X        unless $okay;
  876. X}
  877. X#--------------------------------------------------------------------------
  878. X# check_target -- check to make sure target directory is legitimate,
  879. X#                 exit with an error message if it is not.
  880. X#
  881. X# usage:   &check_target($target)
  882. X# Global variables used:  @safedir
  883. X
  884. Xsub check_target {
  885. X    local($target) = @_;
  886. X    local($okay, $safe);
  887. X
  888. X    $okay = 0;
  889. X    # Disallow ".." to keep from climbing up out of @safedir.
  890. X    $okay = 0 if ($target =~ m#(^|/)\.\.(/|$)#);
  891. X    # Require that $target falls within @safedir.
  892. X    $target .= "/";
  893. X    SAFELOOP:
  894. X    foreach $safe (@safedir) {
  895. X        if ($target =~ m#^$safe/#) {
  896. X            $okay = 1;
  897. X            last SAFELOOP;
  898. X        }
  899. X    }
  900. X    &abend("Data not accepted for Gopher: bad target directory",
  901. X             $error_msg . "Bad target directory: $target\n")
  902. X        unless $okay;
  903. X}
  904. X#--------------------------------------------------------------------------
  905. X# delete_it -- perform requested deletion of an item in Gopherspace
  906. X#
  907. X# usage:  &delete_it()
  908. X# Global variables used:
  909. X#      $filename $subject $target
  910. X
  911. Xsub delete_it {
  912. X    local(@deldata);
  913. X
  914. X    # Does the file even exist?
  915. X    &abend("Data not deleted from Gopher due to error",
  916. X        $del_err_msg . "File does not exist: $target/$filename\n")
  917. X        unless ( -f "$target/$filename" );
  918. X
  919. X    # Slurp up a copy of data to be deleted.  Yes, this is potentially
  920. X    # a big waste of memory.  We should probably copy it or move it
  921. X    # instead (maybe even keep a backup), but we're feeling simple-minded
  922. X    # today.
  923. X    open (DATA, "< $target/$filename");
  924. X    @deldata = <DATA>;
  925. X    close(DATA);
  926. X
  927. X    # Nuke it, and its .cap file too.
  928. X    unlink("$target/.cap/$filename");
  929. X    &abend("Data not deleted from Gopher due to error",
  930. X        $del_err_msg . "Could not delete file $target/$filename\n$@")
  931. X        unless (unlink("$target/$filename"));
  932. X
  933. X    # Success -- give positive feedback and exit.
  934. X    open (MAIL, "| $MAIL $debug_admin '$sender'");
  935. X    print MAIL "Subject: Data deleted from Gopher: \"$subject\"\n\n";
  936. X    print MAIL "$del_ack_msg\n$sig\n";
  937. X    print MAIL "$delsep\n";
  938. X    print MAIL "Title:  $subject\n";
  939. X    print MAIL "File:   $target/$filename\n\n";
  940. X    print MAIL "@deldata";
  941. X    print MAIL "$delend\n\n";
  942. X    print MAIL "$subsep\n";
  943. X    print MAIL "$header";
  944. X    print MAIL "$body";
  945. X    print MAIL "$subend\n";
  946. X    close(MAIL);
  947. X    exit(0);
  948. X}
  949. X#--------------------------------------------------------------------------
  950. X# Subroutine expand
  951. X#     expand a line (To, Cc, etc.) into a list of addressees.
  952. X#
  953. X# [Borrowed with thanks from the "audit.pl" package by Martin Streicher
  954. X#  (strike@convex.com), revision 1.9, 92/05/01.]
  955. X#
  956. Xsub expand {
  957. X    local($_) = @_;
  958. X    local(@fccs) = ( );
  959. X
  960. X    return(@fccs) if /^$/;
  961. X
  962. X    for (split(/\s*,\s*/)) {
  963. X    s/.*<([^>]+)>.*/$1/;
  964. X    s/@.*//;
  965. X    s/.*!//;
  966. X    s/\(.*\)//;
  967. X    s/\s//g;
  968. X    push(@fccs,$_) unless $seen{$_}++;
  969. X    } 
  970. X
  971. X    return(@fccs);
  972. X} 
  973. X#--------------------------------------------------------------------------
  974. X# feedback -- mail the accepted item back to the user
  975. X#             (and to the $debug_admin, if defined)
  976. X#
  977. X# usage:  &feedback()
  978. X# Global variables used:
  979. X#      $accept_msg $body $byline $diclaimer $debug_admin $filename
  980. X#         $header $MAIL $sender $subend $subsep $target
  981. X
  982. Xsub feedback {
  983. X    open (MAIL, "| $MAIL $debug_admin '$sender'");
  984. X    print MAIL "Subject: Data submitted to Gopher: \"$subject\"\n\n";
  985. X    print MAIL "$accept_msg\n$sig\n";
  986. X    print MAIL "$subsep\n";
  987. X    print MAIL "Title:  $subject\n";
  988. X    print MAIL "File:   $target/$filename\n\n";
  989. X    print MAIL "$header";
  990. X    print MAIL "$body";
  991. X    print MAIL "$byline";
  992. X    print MAIL "$disclaimer\n" if ($disclaimer);
  993. X    print MAIL "$subend\n";
  994. X    close(MAIL);
  995. X}
  996. X#--------------------------------------------------------------------------
  997. X# normalize -- convert a title to something good for a filename
  998. X
  999. Xsub normalize {
  1000. X        local($str) = @_;
  1001. X        $str =~ s/\s/_/g;             # change white space to _
  1002. X        $str =~ tr/\/&\\/+/;             # change ands and slashes to +
  1003. X        $str =~ tr/#%+,\-.0-9:;=@A-Z[]_a-z~/#/c; # change trouble to #
  1004. X        $str;
  1005. X}
  1006. X#--------------------------------------------------------------------------
  1007. X# parse_delete -- see if the subject line specifies a deletion request
  1008. X#
  1009. X# Check whether the subject line begins with "delete" or "DELETE".
  1010. X# If not, return 0; if so, remove the "delete" keyword from the $subject
  1011. X# variable and return 1.
  1012. X#
  1013. X# usage:  $delete = &parse_delete()
  1014. X# Global variables used: $subject
  1015. X
  1016. Xsub parse_delete {
  1017. X    local($firstword, $rest);
  1018. X    ($firstword, $rest) = split(/\s+/, $subject, 2);
  1019. X    $firstword =~ tr/A-Z/a-z/;
  1020. X    if ($firstword eq "delete") {
  1021. X        $subject = $rest;
  1022. X        return 1;
  1023. X    }
  1024. X    return 0;
  1025. X}
  1026. X#--------------------------------------------------------------------------
  1027. X# parse_date -- parse a date on the subject line
  1028. X#
  1029. X# This has a side effect: it inserts a weekday into $subject.
  1030. X# It also abends with a message in case of error.
  1031. X#
  1032. X# We try to be flexible in parsing dates.  Here are some formats accepted:
  1033. X#    92-12-30: This is the preferred format
  1034. X#    92/12/30 : (Wed) : But we can handle other separators and a weekday
  1035. X#       1992-12-30: We accept the year with or without the century
  1036. X#    1-1-1 This is a minimalist January 1, 2001
  1037. X#
  1038. X# These will all result in a new subject like this:
  1039. X#    1992-12-30 (Wed): The way things will look in Gopher
  1040. X#
  1041. X# usage:  &parse_date()
  1042. X# Global variables used: $caldir $caldir_by_date $date_msg $subject $target
  1043. X
  1044. Xsub parse_date {
  1045. X    local($date, $gooddate, $yy, $mm, $dd, $title);
  1046. X    $gooddate = 0;
  1047. X    if ($subject =~ /^\s*(\d?\d?\d?\d)\D(\d?\d)\D(\d?\d)\s*:?\s*(.*)/) {
  1048. X        $year = $1;
  1049. X        $mm = $2;
  1050. X        $dd = $3;
  1051. X        $title = $4;
  1052. X    }
  1053. X
  1054. X    # Force the portions of the date into (at least) two-digit form.
  1055. X    $year = "0" . $year if (length($year) == 1);
  1056. X    $mm = "0" . $mm if (length($mm) == 1);
  1057. X    $dd = "0" . $dd if (length($dd) == 1);
  1058. X
  1059. X    # Add a century if it is missing.
  1060. X    if ($year < 100) {
  1061. X        if ($year > 70) {
  1062. X            # We're in the waning years of the 20th century
  1063. X            $year += 1900;
  1064. X        } else {
  1065. X            # You mean somebody's still using this program?
  1066. X            $year += 2000;
  1067. X        }
  1068. X    } 
  1069. X
  1070. X    # Don't accept ancient history or Martian calendars
  1071. X    &abend("Data not accepted for Gopher: bad date", $date_msg)
  1072. X        unless ($year >= 1970 && $mm >= 1 && $mm <= 12 && 
  1073. X            $dd >= 1 && $dd <=31);
  1074. X
  1075. X    # Discard a weekday if one followed the date on the subject line.
  1076. X    # Note the final whitespace in the pattern: we don't want to mess up
  1077. X    # a subject like "93-06-01 Wedding bells for Sarah and Jim"!
  1078. X    $title =~ s/^\(?(Mon|mon|Tue|tue|Wed|wed|Thu|thu|Fri|fri|Sat|sat|Sun|sun)\)?\s*:?\s+//;
  1079. X
  1080. X    # Set the global $subject and $target.
  1081. X    $date = "$year-$mm-$dd";
  1082. X    $weekday = &weekday($year, $mm, $dd);
  1083. X    $subject = "$date ($weekday): $title";
  1084. X}
  1085. X#--------------------------------------------------------------------------
  1086. X# Subroutine parse_email_address
  1087. X#    Parse an email address into address, from, organization
  1088. X#    address is full Internet address, from is just the login
  1089. X#    name and organization is Internet hostname (without final domain)
  1090. X#
  1091. X# [Borrowed with thanks from the "audit.pl" package by Martin Streicher
  1092. X#  (strike@convex.com), revision 1.9, 92/05/01.]
  1093. X#
  1094. Xsub parse_email_address {
  1095. X    local($_) = @_;
  1096. X    local($friendly, $address, $from, $organization);
  1097. X
  1098. X    $organization = "local";
  1099. X    $friendly = "unknown";
  1100. X
  1101. X# From: Disk Monitor Daemon (/usr/adm/bin/dfbitch) <daemon@hydra.convex.com>?
  1102. X
  1103. X    s/^\s*//;
  1104. X    s/\s*$//;
  1105. X    if (/(.*)\s*<[^>]+>$|<[^>]+>\s*(.*)$/) {
  1106. X    $friendly = $+;
  1107. X    $friendly =~ s/\"//g;
  1108. X    } elsif (/\(([^\)]+)\)/) {
  1109. X    $friendly = $1;
  1110. X    };
  1111. X
  1112. X    s/.*<([^>]+)>.*/$1/;
  1113. X    s/\(.*\)//;
  1114. X    s/\s*$//;
  1115. X    $address = $_;
  1116. X
  1117. X    s/@.*//;
  1118. X    s/%.*//;
  1119. X    s/.*!//;
  1120. X    s/\s//g;
  1121. X    $from = $_;
  1122. X
  1123. X    $_ = $address;
  1124. X    tr/A-Z/a-z/;
  1125. X    if (/!/ && /@/) {
  1126. X        s/\s//g;
  1127. X        s/!.*//;
  1128. X        $organization = $_;
  1129. X    } elsif (/!/) {
  1130. X        s/\s//g;
  1131. X        s/![A-Za-z0-9_@]*$//;
  1132. X        s/.*!//;
  1133. X        s/\..*//;
  1134. X        $organization = $_;
  1135. X    } elsif (/@/) {
  1136. X        s/.*@//;
  1137. X        s/\s//g;
  1138. X        if (! /\./) {
  1139. X            $organization = "unknown";
  1140. X        } else {
  1141. X            if (/\.(com|edu)$/) {
  1142. X                s/\.[A-Za-z0-9_]*$//;
  1143. X                s/.*\.//;
  1144. X            } else {
  1145. X                s/\.[A-Za-z0-9_]*$//;
  1146. X                s/\.[A-Za-z0-9_]*$//;
  1147. X                s/.*\.//;
  1148. X            };
  1149. X            $organization = $_;
  1150. X        };
  1151. X    };
  1152. X
  1153. X    return ($friendly, $address, $from, $organization);
  1154. X};
  1155. X#--------------------------------------------------------------------------
  1156. X# Subroutine parse_message
  1157. X#    Parse a message into headers, body and special variables
  1158. X#
  1159. X# [Borrowed with thanks from the "audit.pl" package by Martin Streicher
  1160. X#  (strike@convex.com), revision 1.9, 92/05/01.]
  1161. X#
  1162. Xsub parse_message {
  1163. X    local(*INFILE) = @_;
  1164. X
  1165. X    $/ = '';        # read input in paragraph mode
  1166. X    %headers = ( );
  1167. X    @received = ( );
  1168. X
  1169. X    $header = <INFILE>;
  1170. X
  1171. X    $* = 1;
  1172. X    while (<INFILE>) { 
  1173. X    s/^From />From /g;
  1174. X    $body = "" if !defined($body);
  1175. X    $body .= $_; 
  1176. X    };
  1177. X    $/ = "\n";        
  1178. X    $* = 0;
  1179. X
  1180. X
  1181. X    ;# -----
  1182. X    ;# $sender comes from the UNIX-style From line (From strike...)
  1183. X    ;#
  1184. X    ($sender) = ($header =~ /^From\s+(\S+)/); 
  1185. X
  1186. X
  1187. X    ;# -----
  1188. X    ;# fill out the headers associative array with fields from the mail
  1189. X    ;# header.
  1190. X    ;#
  1191. X    $_ = $header;
  1192. X    s/\n\s+//g;
  1193. X    @lines = split('\n');
  1194. X    for ( @lines ) {
  1195. X    /^(\w*):\s*(.*)/ && do {
  1196. X        $mheader = $1;
  1197. X        $mheader =~ tr/A-Z/a-z/;
  1198. X        if (($mheader eq "cc" || $mheader eq "to") && $headers{$mheader}) {
  1199. X        $headers{$mheader} .= ", $2";
  1200. X        } elsif ($mheader eq "received") {
  1201. X        push(@received, $2);
  1202. X        } else {
  1203. X        $headers{$mheader} = $2;
  1204. X        };
  1205. X    };
  1206. X    }
  1207. X    @received = reverse(@received);
  1208. X
  1209. X
  1210. X    ;# -----
  1211. X    ;# for convenience, $subject is $headers{'subject'} and $precedence is
  1212. X    ;# $headers{'precedence'}
  1213. X    ;#
  1214. X    $subject = $headers{'subject'};
  1215. X    $subject = "(No subject)" unless $subject;
  1216. X    $subject =~ s/\s+$//;
  1217. X    $precedence = $headers{'precedence'};
  1218. X
  1219. X
  1220. X    ;# -----
  1221. X    ;# $from comes from From: line. $address is their email address.
  1222. X    ;# $organization is their site. for example, strike@pixel.convex.com 
  1223. X    ;# yields an organization of convex.
  1224. X    ;#
  1225. X    $_ = $headers{'from'} ||
  1226. X         $headers{'resent-from'} ||
  1227. X         $headers{'sender'} ||
  1228. X         $headers{'resent-sender'} ||
  1229. X         $headers{'return-path'} ||
  1230. X         $headers{'reply-to'};
  1231. X
  1232. X    if ($_ eq "") {
  1233. X       $from = $address = $organization = "unknown";
  1234. X       return;
  1235. X    };
  1236. X
  1237. X    ($friendly, $address, $from, $organization) = &parse_email_address($_);
  1238. X
  1239. X    ;# -----
  1240. X    ;# create arrays for who was on the To, Cc lines
  1241. X    ;#
  1242. X    @to = &expand($headers{'to'}); 
  1243. X    push(@to, &expand($headers{'apparently-to'}));
  1244. X    @cc = &expand($headers{'cc'});
  1245. X}
  1246. X#--------------------------------------------------------------------------
  1247. X# weekday -- given a date, return the three-letter name of a weekday
  1248. X#
  1249. X# usage:  &weekday($year, $mm, $dd)
  1250. X
  1251. Xsub weekday {
  1252. X    local($year, $mm, $dd) = @_;
  1253. X    local($datestr);
  1254. X    $year -= 1900;            # tz structure expects years - 1900
  1255. X    $mm -= 1;            # tz struct expects months to be 0-11;
  1256. X    $datestr = &ctime(&timelocal(1, 1, 1, $dd, $mm, $year, "", "", 0));
  1257. X    return(substr($datestr, 0, 3));
  1258. X}
  1259. X#--------------------------------------------------------------------------
  1260. X# write_it -- write the data to Gopherspace (along with a .cap file)
  1261. X#
  1262. X# usage:  &write_it()
  1263. X# Global variables used:
  1264. X#      $body $byline $disclaimer $error_msg $filename $subject $target
  1265. X#
  1266. X# SIDE EFFECT: We chdir() to the $target directory.
  1267. X# Thanks to Fred Barrie (barrie@futique.scs.unr.edu) for supplying the fix
  1268. X# for a peculiar perl bug: it can't open a file with a fully-defined path
  1269. X# longer than 64 characters.
  1270. X
  1271. Xsub write_it {
  1272. X
  1273. X    chdir($target) ||
  1274. X        &abend("Data not accepted for Gopher due to gmail error",
  1275. X            $error_msg . "Can't chdir to directory $target\n$@");
  1276. X    open (FILE, "> $filename") ||
  1277. X        &abend("Data not accepted for Gopher due to gmail error",
  1278. X            $error_msg . "Can't open file $target/$filename\n$@");
  1279. X    print FILE "$subject\n\n";
  1280. X    print FILE $body;
  1281. X    print FILE "$byline";
  1282. X    print FILE "$disclaimer\n" if ($disclaimer);
  1283. X    close(FILE);
  1284. X
  1285. X    # Make a .cap file only if one is needed.
  1286. X    if ($subject ne $filename) {
  1287. X        unless (-d ".cap") {
  1288. X            mkdir(".cap", 0755);
  1289. X        }
  1290. X        unless (open (FILE, "> .cap/$filename")) {
  1291. X            # Can't create .cap file -- complain and clean up
  1292. X            unlink("$filename");
  1293. X            &abend("Data not accepted for Gopher due to gmail error",
  1294. X                $error_msg . "Can't open file $target/.cap/$filename\n$@");
  1295. X        }
  1296. X        print FILE "Name=$subject\n";
  1297. X        close(FILE);
  1298. X    }
  1299. X}
  1300. X#--------------------------------------------------------------------------
  1301. X
  1302. X# end of gmail script
  1303. END_OF_FILE
  1304. if test 26490 -ne `wc -c <'gmail'`; then
  1305.     echo shar: \"'gmail'\" unpacked with wrong size!
  1306. fi
  1307. chmod +x 'gmail'
  1308. # end of 'gmail'
  1309. fi
  1310. if test -f 'gmailcal' -a "${1}" != "-c" ; then 
  1311.   echo shar: Will not clobber existing file \"'gmailcal'\"
  1312. else
  1313. echo shar: Extracting \"'gmailcal'\" \(12517 characters\)
  1314. sed "s/^X//" >'gmailcal' <<'END_OF_FILE'
  1315. X#!/usr/local/bin/perl
  1316. X#
  1317. X#  gmailcal: nightly process to generate alternate views of events
  1318. X#             submitted with gmail(8)
  1319. X#
  1320. X#  usage:  gmailcal
  1321. X#
  1322. X#  PASR 01/29/93  Original version (Prentiss Riddle, riddle@rice.edu).
  1323. X#  PASR 02/03/93  Declared this release 0.2 and sent it out for beta
  1324. X#                 testing.
  1325. X#  PASR 02/22/93  Declared this release 1.0 for general use.
  1326. X#  PASR 02/24/93  Portability fix: match year in ctime() results with a
  1327. X#                 pattern rather than a substr() call.
  1328. X#  PASR 03/07/93  Defined umask in the configuration section.
  1329. X#  PASR 03/29/93  Fixed bug in calculation of week cuts.
  1330. X#                 Declared this version 1.01.
  1331. X#
  1332. X#  TODO: Make sure all old .cache files get deleted when gmailcal is run.
  1333. X#  TODO: Think about including a command-line option which causes header
  1334. X#        info to be read from a file, allowing a single installation to
  1335. X#        be used in multiple configurations (in particular, to allow 
  1336. X#        multiple events calendars).
  1337. X#  TODO: Think about putting a chmod in &fixcap.
  1338. X
  1339. X#--------------------------------------------------------------------------
  1340. X# CONFIGURATION: modify these to suit your site!
  1341. X
  1342. X# Raw calendar data live under here.  Note that the alternate views will
  1343. X# be *sibling* directories to this one!
  1344. X$caldir = "/foo/cwis/gopher/world/Calendars/Events/Upcoming";
  1345. X
  1346. X# Gopher link information: a Gopher's-eye view of the same directory
  1347. X# specified in $caldir.
  1348. X$Host = "cwis.foobar.edu";
  1349. X$Port = 70;
  1350. X$Path = "1/Calendars/Events/Upcoming";
  1351. X
  1352. X# How many days will we keep old events around in the "../Past" directory?
  1353. X$keepold = 183;
  1354. X
  1355. X# On which day does the week begin?  (0=Sunday, 1=Monday)
  1356. X$weekbreak = 1;
  1357. X
  1358. X# How many months ahead will we maintain month-by-month views?
  1359. X$monthviews = 5;
  1360. X
  1361. X# Short description of this events calendar
  1362. X# (e.g., "the Foobar University events schedule")
  1363. X$description = "the Foobar University events calendar";
  1364. X
  1365. X# Turn on for noisy output, off for only serious error messages.
  1366. X$debug = 0;
  1367. X
  1368. X# Umask: the Unix file permissions mask.  Use 002 if you wish to have
  1369. X# files created by gmailcal be group-writeable, 022 otherwise.
  1370. X$UMASK = 022;
  1371. X
  1372. X#--------------------------------------------------------------------------
  1373. X# Further initialization (you should probably leave this alone):
  1374. X
  1375. Xrequire "ctime.pl";
  1376. X
  1377. X@monthnames =
  1378. X     ("January", "February", "March", "April", "May", "June",
  1379. X      "July", "August", "September", "October", "November", "December");
  1380. X
  1381. X# Recursive "rm" command (very scary!)
  1382. X$rm = "/bin/rm -r -f";
  1383. X
  1384. Xumask $UMASK;
  1385. X
  1386. X# Master "About" file.  We will put a link to this in each of the alternate
  1387. X# view subdirectories.
  1388. X$about = $caldir;
  1389. X$about =~ s#(.*)/.*#$1/About#;
  1390. Xprint(STDERR "Warning: \"About\" file $about missing\n") unless (-f $about);
  1391. X
  1392. X#--------------------------------------------------------------------------
  1393. X#
  1394. X# Here's the directory structure we're shooting for:
  1395. X#
  1396. X# Foobar Events/
  1397. X#    About the Foobar events schedule
  1398. X#    Search the Foobar events schedule <?>
  1399. X#    Today/
  1400. X#    Tomorrow/
  1401. X#    This week/
  1402. X#    Next week/
  1403. X#    January, 1993/
  1404. X#    February, 1993/
  1405. X#    March, 1993/
  1406. X#    ...
  1407. X#    All upcoming events/
  1408. X#    Past events/
  1409. X
  1410. X# We do all of our work relative to $chdir.
  1411. Xchdir($caldir) || die("Couldn't chdir to $caldir: $!");
  1412. X
  1413. X# Get various date information relative to today's date.
  1414. X$daysec = 24 * 60 * 60;
  1415. X$clocktime = time;
  1416. X$weekday = substr(&ctime($clocktime), 0, 3);
  1417. X$wkdint = index("SunMonTueWedThuFriSat", $weekday) / 3;
  1418. Xdie("Unrecognized weekday: $weekday") if ($wkdint < 0);
  1419. X
  1420. X$today = &yyyymmdd($clocktime);
  1421. X$tomorrow = &yyyymmdd($clocktime + $daysec);
  1422. X$pastcut = &yyyymmdd($clocktime - $keepold * $daysec);
  1423. X$thisweekcut = &yyyymmdd($clocktime + (6 - $wkdint + $weekbreak) * $daysec);
  1424. X$nextweekcut = &yyyymmdd($clocktime + (13 - $wkdint + $weekbreak) * $daysec);
  1425. X
  1426. X$mm = substr($today, 5, 2);
  1427. X$yyyy = substr($today, 0, 4);
  1428. X$monthcuts[0] = substr($today, 0, 7);
  1429. Xfor ($i = 1 ; $i < $monthviews ; $i++) {
  1430. X    #$mm .= "";    # Force into a string context!
  1431. X    $mm++;
  1432. X    if ($mm gt "12") {
  1433. X        $mm = "01";
  1434. X        $yyyy++;
  1435. X    }
  1436. X    $monthcuts[$i] = $yyyy . "-" . $mm;
  1437. X}
  1438. X
  1439. X# Delete old month directories and corresponding .cap files.
  1440. Xopendir(PARENT, "..") || die("Couldn't open parent directory: $!");
  1441. Xforeach $dir (grep(/^\d\d\d\d-\d\d$/, readdir(PARENT))) {
  1442. X    print("Deleting: ../$dir ../cap/$dir\n") if $debug;
  1443. X    system("$rm ../$dir");
  1444. X    unlink("../.cap/$dir");
  1445. X}
  1446. Xclosedir(PARENT);
  1447. X
  1448. X# Arrange the directories where the alternate views will go.
  1449. X&fixcap("../About", "About " . $description, 1);
  1450. X$todaydir = "../Today";        &fixdir($todaydir, "Today", 2);
  1451. X$tomorrowdir = "../Tomorrow";  &fixdir($tomorrowdir, "Tomorrow", 3);
  1452. X$thisweekdir = "../This_week"; &fixdir($thisweekdir, "This week", 4);
  1453. X$nextweekdir = "../Next_week"; &fixdir($nextweekdir, "Next week", 5);
  1454. Xfor ($i = 0 ; $i < $monthviews ; $i++) {
  1455. X    $monthdirs[$i] = "../" . $monthcuts[$i];
  1456. X    $monthtitles[$i] = $monthnames[substr($monthcuts[$i], 5, 2) - 1]
  1457. X                       . ", " . substr($monthcuts[$i], 0, 4);
  1458. X    &fixdir($monthdirs[$i], $monthtitles[$i], $i + 6);
  1459. X}
  1460. X&fixcap($caldir, "All upcoming events", $monthviews + 6);
  1461. X$pastdir = "../Past"; &fixdir($pastdir, "Past events", $monthviews + 7);
  1462. X
  1463. X# Open .links files and put a link to the "About" file in each one.
  1464. X&openlink("UPCOMING", "$caldir/.links"); close(UPCOMING);
  1465. X&openlink("PAST", "$pastdir/.links"); close(PAST);
  1466. X&openlink("TODAY", "$todaydir/.links");
  1467. X&openlink("TOMORROW", "$tomorrowdir/.links");
  1468. X&openlink("THISWEEK", "$thisweekdir/.links");
  1469. X&openlink("NEXTWEEK", "$nextweekdir/.links");
  1470. X$month = 0;
  1471. X&openlink("MONTH", "$monthdirs[$month]/.links");
  1472. X
  1473. X# MAIN LOOP: Step through the calendar events in $caldir, creating links
  1474. X#            to them as necessary.
  1475. Xopendir(CALDIR, ".") || die("Couldn't open $caldir: $!");
  1476. XMAINLOOP:
  1477. Xforeach $event sort(grep(/^\d\d\d\d-\d\d-\d\d/, readdir(CALDIR))) {
  1478. X    print("Processing event: \"$event\"\n") if $debug;
  1479. X    $matchdate = substr($event, 0, 10);
  1480. X    if ($matchdate lt $today) {
  1481. X        # Move this event to $pastdir, including its .cap file.
  1482. X        print "Moving past event: \"$event\"\n" if $debug;
  1483. X        rename($event, "$pastdir/$event") || 
  1484. X            die("Can't move $event to $pastdir: $!");
  1485. X        rename(".cap/$event", "$pastdir/.cap/$event");
  1486. X    } else {
  1487. X        # Does the event match today, tomorrow, this or next week?
  1488. X        if ($matchdate eq $today) {
  1489. X            &makelink($event, "TODAY");
  1490. X        } elsif ($matchdate eq $tomorrow) {
  1491. X            &makelink($event, "TOMORROW");
  1492. X        }
  1493. X        if ($matchdate le $thisweekcut) {
  1494. X            &makelink($event, "THISWEEK");
  1495. X        } elsif ($matchdate gt $thisweekcut && $matchdate le $nextweekcut) {
  1496. X            &makelink($event, "NEXTWEEK");
  1497. X        }
  1498. X        # Match "../yyyy-mm" against the current $monthdirs[].
  1499. X        $matchdate = "../" . substr($event, 0, 7);
  1500. X        while ($matchdate gt $monthdirs[$month] && $month < $monthviews - 1) {
  1501. X            # New month.
  1502. X            $month++;
  1503. X            close(MONTH);
  1504. X            &openlink("MONTH", "$monthdirs[$month]/.links");
  1505. X        }
  1506. X        if ($matchdate eq $monthdirs[$month]) {
  1507. X            &makelink($event, "MONTH");
  1508. X        }
  1509. X    }
  1510. X}
  1511. Xclosedir(CALDIR);
  1512. Xclose(TODAY);
  1513. Xclose(TOMORROW);
  1514. Xclose(THISWEEK);
  1515. Xclose(NEXTWEEK);
  1516. Xclose(MONTH);
  1517. X
  1518. X# Remove ancient events from the "Past events" directory (including
  1519. X# their .cap files).
  1520. Xopendir(PAST, $pastdir) || die("Couldn't open directory $pastdir: $!");
  1521. XPASTLOOP:
  1522. Xforeach $event (grep(/^\d\d\d\d-\d\d-\d\d/, readdir(PAST))) {
  1523. X    if ($event lt $pastcut) {
  1524. X        print("Deleting old event: $pastdir/$event\n") if $debug;
  1525. X        unlink("$pastdir/$event");
  1526. X        unlink("$pastdir/.cap/$event");
  1527. X    }
  1528. X}
  1529. Xclosedir(PAST);
  1530. X
  1531. X#--------------------------------------------------------------------------
  1532. X# fixcap -- fill out a ".cap" file, given a filename, title and position
  1533. X#
  1534. X# usage:  &fixcap($filename, $title, $position);
  1535. X
  1536. Xsub fixcap {
  1537. X    local($filename, $title, $position) = @_;
  1538. X    local($dirname);
  1539. X
  1540. X    print "fixcap(\"$filename\", \"$title\", $position);\n" if $debug;
  1541. X    # Insert ".cap/" in the filename.
  1542. X    $filename =~ s#(.*)/(.*)#$1/.cap/$2#;
  1543. X    $dirname = $filename;
  1544. X    $dirname =~ s#(.*/\.cap)/.*#$1#;
  1545. X    unless (-d $dirname) {
  1546. X        mkdir($dirname, 0755) ||
  1547. X            die("Can't create .cap directory $dirname: $!");
  1548. X    }
  1549. X    open (CAP, "> $filename") || die("Can't open .cap file $filename: $!");
  1550. X    print(CAP "Name=$title\nNumb=$position\n");
  1551. X    close (CAP);
  1552. X}
  1553. X#--------------------------------------------------------------------------
  1554. X# fixdir -- prepare a directory which is to contain an alternate view
  1555. X#
  1556. X# Side effects:
  1557. X# -- creates the named directory, if necessary
  1558. X# -- creates a ".cap" subdirectory within the named directory, if necessary
  1559. X# -- deletes a ".links" file within the named directory, if necessary
  1560. X# -- calls &fixcap to set the title and position of the named directory
  1561. X#    within its parent directory
  1562. X#
  1563. X# usage: &fixdir($directory, $title, $position);
  1564. X
  1565. Xsub fixdir {
  1566. X    local($directory, $title, $position) = @_;
  1567. X
  1568. X    unless (-d $directory) {
  1569. X        mkdir($directory, 0755) || 
  1570. X            die("Can't create directory $directory: $!");
  1571. X    }
  1572. X    unless (-d "$directory/.cap") {
  1573. X        mkdir("$directory/.cap", 0755) || 
  1574. X            die("Can't create directory $directory/.cap: $!");
  1575. X    }
  1576. X    unlink("$directory/.links") if (-f "$directory/.links");
  1577. X    print "fixdir(\"$directory\", \"$title\", $position);\n" if $debug;
  1578. X    &fixcap($directory, $title, $position);
  1579. X}
  1580. X#--------------------------------------------------------------------------
  1581. X# makelink -- make a link to a given event in a given .links file
  1582. X#
  1583. X# usage: &makelink($event, $filehandle);
  1584. X#
  1585. X# global variables used: $caldir $Host $Port $Path $eventpath $debug
  1586. X
  1587. Xsub makelink {
  1588. X    local($event, $fh) = @_;
  1589. X    local($name);
  1590. X
  1591. X    print "makelink(\"$event\", \"$fh\");\n" if $debug;
  1592. X
  1593. X    # Read the name from the .cap file corresponding to the event.
  1594. X    open(CAP, "< $caldir/.cap/$event");
  1595. X    CAPLOOP:
  1596. X    while (<CAP>) {
  1597. X        if (/^Name=/) {
  1598. X            $name = $_;
  1599. X            $name =~ s/^Name=//;
  1600. X            last CAPLOOP;
  1601. X        }
  1602. X    }
  1603. X    close(CAP);
  1604. X
  1605. X    # Complain and exit if we couldn't read it.
  1606. X    unless ($name) {
  1607. X        print(STDERR "Error: Couldn't read .cap file for $event\n");
  1608. X        return;
  1609. X    }
  1610. X
  1611. X    print($fh "#\n");
  1612. X    print($fh "Name=$name");
  1613. X    print($fh "Host=$Host\n");
  1614. X    print($fh "Type=0\n");
  1615. X    print($fh "Port=$Port\n");
  1616. X    unless ($eventpath) {
  1617. X        $eventpath = $Path;
  1618. X        $eventpath =~ s/^1/0/;
  1619. X    }
  1620. X    print($fh "Path=$eventpath/$event\n");
  1621. X}
  1622. X#--------------------------------------------------------------------------
  1623. X# monthindex -- given a three-character month abbreviation, return the
  1624. X#               corresponding integer "01" (January) to "12" (December)
  1625. X#
  1626. X# usage: $mm = &monthindex($monthstr);
  1627. X# error: return -1 in case of error;
  1628. X
  1629. Xsub monthindex {
  1630. X    local($monthstr) = @_;
  1631. X    local($mm);
  1632. X    $monthstr =~ tr/A-Z/a-z/;
  1633. X    $mm = index("janfebmaraprmayjunjulaugsepoctnovdec", $monthstr) / 3 + 1;
  1634. X    $mm = -1 if ($mm <= 0 || $mm > 12);
  1635. X    $mm = "0" . $mm if ($mm > 0 && $mm < 10);
  1636. X    return $mm;
  1637. X}
  1638. X#--------------------------------------------------------------------------
  1639. X# openlink -- open a ".links" file
  1640. X#
  1641. X# usage:  &openlink($filehandle, $filename);
  1642. X#
  1643. X# Global variables used:  $about $description $Host $Port $Path $aboutpath
  1644. X#
  1645. X# Side effects:
  1646. X# -- Opens the .links file specified by $filename
  1647. X# -- Writes to it a link to the "About" file
  1648. X
  1649. Xsub openlink {
  1650. X    local($fh, $filename) = @_;
  1651. X
  1652. X    print "openlink(\"$fh\", \"$filename\");\n" if $debug;
  1653. X    open($fh, "> $filename") || 
  1654. X        die("Can't open .links file $filename: $!");
  1655. X    print($fh "# This file is automatically generated. Don't touch!\n");
  1656. X    print($fh "#\n");
  1657. X    # Kluge alert: for some reason "Numb=1" doesn't work here, so
  1658. X    # we resort to the old initial-space-in-a-Name trick. :-(
  1659. X    print($fh "Name= About $description\n");
  1660. X    #print($fh "Numb=1\n");
  1661. X    print($fh "Type=0\n");
  1662. X    print($fh "Host=$Host\n");
  1663. X    print($fh "Port=$Port\n");
  1664. X    unless ($aboutpath) {
  1665. X        $aboutpath = $Path;
  1666. X        $aboutpath =~ s#(.*)/.*#$1/About#;
  1667. X        $aboutpath =~ s/^1/0/;
  1668. X    }
  1669. X    print($fh "Path=$aboutpath\n");
  1670. X}
  1671. X#--------------------------------------------------------------------------
  1672. X# yyyymmdd -- given a clocktime (in seconds since the epoch), return the
  1673. X#             corresponding date in the format "yyyy-mm-dd"
  1674. X#
  1675. X# usage: $date = &yyyymmdd($clocktime);
  1676. X#
  1677. X#
  1678. X# Portability issue: we count on &ctime() to return the date in one of
  1679. X# the two following formats:
  1680. X#
  1681. X#    Wed Feb 24 10:42:22 1993
  1682. X#    Wed Feb 24 10:42:22 CST 1993
  1683. X#
  1684. X# If it doesn't, we're in trouble...
  1685. X
  1686. Xsub yyyymmdd {
  1687. X    local($clocktime) = @_;
  1688. X    local($date, $yyyy, $mm, $dd);
  1689. X    $date = &ctime($clocktime);
  1690. X    ($yyyy) = $date =~ /\s(\d\d\d\d)\s*$/;
  1691. X    $mm = &monthindex(substr($date, 4, 3));
  1692. X    $dd = substr($date, 8, 2);
  1693. X    $dd =~ s/ /0/;
  1694. X    return($yyyy . "-" . $mm . "-" . $dd);
  1695. X}
  1696. X#--------------------------------------------------------------------------
  1697. X# end of gmailcal script
  1698. END_OF_FILE
  1699. if test 12517 -ne `wc -c <'gmailcal'`; then
  1700.     echo shar: \"'gmailcal'\" unpacked with wrong size!
  1701. fi
  1702. chmod +x 'gmailcal'
  1703. # end of 'gmailcal'
  1704. fi
  1705. if test -f 'gmailbatch' -a "${1}" != "-c" ; then 
  1706.   echo shar: Will not clobber existing file \"'gmailbatch'\"
  1707. else
  1708. echo shar: Extracting \"'gmailbatch'\" \(2594 characters\)
  1709. sed "s/^X//" >'gmailbatch' <<'END_OF_FILE'
  1710. X#!/usr/local/bin/perl
  1711. X#  Change the above to point to your site's perl installation.
  1712. X#
  1713. X#  gmailbatch -- script to aid in batch submissions to gmail
  1714. X#
  1715. X#
  1716. X#  usage:   gmailbatch destination < inputfile
  1717. X#
  1718. X#  where "destination" is the email alias of a gmail server
  1719. X#
  1720. X#        "inputfile" is a collection of messages to be sent to gmail,
  1721. X#     separated by lines beginning with "%%".  The remainder of a
  1722. X#     "%%" line is taken to be the subject of the following message.
  1723. X#     If the remainder of the "%%" line is blank, then the first
  1724. X#     line of the message is also used as the subject.
  1725. X#
  1726. X#  Examples:
  1727. X#
  1728. X#  gmailbatch cwis@foobar.edu <<EOF
  1729. X#  %%About apples and oranges
  1730. X#  This directory contains information on apples and oranges.
  1731. X#  %%Apples
  1732. X#  Apples are red or green on the outside and white on the inside.
  1733. X#  Johnny Appleseed used to plant them.
  1734. X#  %%
  1735. X#  Oranges
  1736. X#
  1737. X#  Oranges are orange on the outside and divided into sections on the
  1738. X#  inside.  Anita Bryant used to sing about them.
  1739. X#  EOF
  1740. X#
  1741. X#
  1742. X#  gmailbatch events@foobar.edu <<EOF
  1743. X#  %%1993-03-17 St. Patrick's Day at the Coffeehouse
  1744. X#  Drink green near-beer and sing along with Toby O'Brien at the
  1745. X#  Coffeehouse, 8:00 p.m.
  1746. X#  %%1993-07-04 Independence Day fireworks at Town Lake
  1747. X#  Fireworks for the whole family on the lake.  Sponsored by the
  1748. X#  Volunteer Fire Brigade.
  1749. X#  EOF
  1750. X#
  1751. X#
  1752. X#-------------------------------------------------------------------------
  1753. X#
  1754. X#  Author: Prentiss Riddle (riddle@rice.edu).
  1755. X#
  1756. X#  History:
  1757. X#  02/15/93  PASR  Original version based on smug 0.1.
  1758. X#  
  1759. X#-------------------------------------------------------------------------
  1760. X
  1761. X$separator = '%%';
  1762. X$sendmail = "/usr/lib/sendmail";
  1763. X$usage = "usage: gmailbatch destination\n";
  1764. X
  1765. Xunless ($#ARGV == 0) {
  1766. X    print STDERR "$usage";
  1767. X    exit(1);
  1768. X}
  1769. X$mailto = $ARGV[0];
  1770. Xprint "Mailing the following items to $mailto:\n";
  1771. X
  1772. X$error = 0;
  1773. X$skip = 1;
  1774. XMAINLOOP:
  1775. Xwhile (<STDIN>) {
  1776. X    chop;
  1777. X    if (/^$separator/) {
  1778. X        close (CURFILE) unless $skip;
  1779. X        s/^$separator//;
  1780. X        if ($_ eq "") {
  1781. X            # no title -- cannibalize first line of text block
  1782. X            $_ = <STDIN>;    # don't chop yet!
  1783. X            if (/^$separator/) {
  1784. X                # uh-oh -- null text block
  1785. X                print "Error: missing title in $dir\n";
  1786. X                $error = 1;
  1787. X                redo MAINLOOP;
  1788. X            }
  1789. X            chop;
  1790. X        }
  1791. X        open (CURFILE, "| $sendmail $mailto") || 
  1792. X            die("Couldn't open pipe to $sendmail: $!");
  1793. X        $skip = 0;
  1794. X        print CURFILE "Subject: $_\n\n";
  1795. X        print "$_\n";
  1796. X    } else {
  1797. X        print CURFILE $_, "\n" unless $skip;
  1798. X    }
  1799. X    
  1800. X} # end MAINLOOP
  1801. Xclose (CURFILE) unless $skip;
  1802. X
  1803. Xexit $error;
  1804. X
  1805. X#------------------------------------------------------------------------
  1806. X
  1807. X# end of gmailbatch script
  1808. END_OF_FILE
  1809. if test 2594 -ne `wc -c <'gmailbatch'`; then
  1810.     echo shar: \"'gmailbatch'\" unpacked with wrong size!
  1811. fi
  1812. chmod +x 'gmailbatch'
  1813. # end of 'gmailbatch'
  1814. fi
  1815. echo shar: End of shell archive.
  1816. exit 0
  1817.  
  1818.  
  1819.